package com.hnxxxy.common.shiro;

import com.hnxxxy.sysmgr.pojo.Staff;
import com.hnxxxy.sysmgr.service.SysService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Set;

/**
 * 自定义Realm
 * （1）AuthenticatingRealm：shiro中的用于进行认证的领域，实现doGetAuthentcationInfo方法实现用户登录时的认证逻辑；
 * （2）AuthorizingRealm：shiro中用于授权的领域，实现doGetAuthrozitionInfo方法实现用户的授权逻辑，AuthorizingRealm继承了AuthenticatingRealm，
 * 所以在实际使用中主要用到的就是这个AuthenticatingRealm类；
 * （3）AuthenticatingRealm、AuthorizingRealm这两个类都是shiro中提供了一些线程的realm接口
 * （4）在与spring整合项目中，shiro的SecurityManager会自动调用这两个方法，从而实现认证和授权，可以结合shiro的CacheManager将认证和授权信息保存在缓存中，
 * 这样可以提高系统的处理效率。
 *
 */
public class UserRealm extends AuthorizingRealm{
    Logger logger = LoggerFactory.getLogger(AuthorizingRealm.class);

    @Autowired
    private SysService userSerivce;

    @Override
    public boolean supports(AuthenticationToken token) {
        if(token instanceof  UsernamePasswordToken){
            return true;
        }
        return false;
    }

    /**
     * 执行认证逻辑
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token1) throws AuthenticationException {
        logger.info("-->执行认证授权");
        //编写shiro判断逻辑，判断用户名和密码
        //1.判断用户名  token中的用户信息是登录时候传进来的
        UsernamePasswordToken token = (UsernamePasswordToken)token1;
        Staff user = userSerivce.findByName(token.getUsername());
        if(user==null){
            //用户名不存在
            return null;//shiro底层会抛出UnKnowAccountException
        }

        //2.判断密码
        ByteSource salt = ByteSource.Util.bytes(user.getSalt());

        //注修改密码的时候可以使用String result = new SimpleHash(hashAlgorithmName, pwd, ByteSource.Util.bytes(salt), hashInteractions).toHex();
        return new SimpleAuthenticationInfo(user,user.getPwd(),salt,this.getName());
    }

    /**
     * 执行授权逻辑
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
        logger.info("-->执行角色和权限授权");
        //给资源进行授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Subject subject = SecurityUtils.getSubject();
        Staff user = (Staff) subject.getPrincipal();
        Set<String> rolesSet= userSerivce.findRolesByStaffId(user.getId());
        Set<String> premsSet= userSerivce.findPremsByStaffId(user.getId());
        info.addRoles(rolesSet);
        info.addStringPermissions(premsSet);
        return info;
    }
}